
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>K8S 中 Alpine镜像中执行 jstack、arthas 等命令提示 Unable to get pid of LinuxThreads manager thread</title>
            </head>
            <body>
            <a href="https://andyoung.blog.csdn.net">原作者博客</a>
            <div id="content_views" class="markdown_views prism-atom-one-light">
                    <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
                        <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
                    </svg>
                    <h3><a id="1__0"></a>1. 问题现象</h3> 
<p>最近在处理项目上问题发现之前同事构建的AlpineLinux的镜像不能执行jstack等JDK命令，报错如下。</p> 
<pre><code class="prism language-bash">Unable to get pid of LinuxThreads manager thread
</code></pre> 
<h3><a id="2__8"></a>2. 问题原因</h3> 
<p>问题的根本原因有两点:</p> 
<ol><li>Alpine Linux 使用的不是标准gnu libc (glibc)，而是musl libc</li><li>apk包管理器安装的OpenJDK是IceTea补丁版本的，已经停止维护了</li></ol> 
<p>这两个原因导致了一个神奇的现象：<code>当Java进程PID＝1时，通过OpenJDK8执行JDK命令调用底层时会提示Unable to get pid of LinuxThreads manager thread</code>，这个错误信息来源于Alpine仓库中OpenJDK源码中的一个失误，没处理musl libc仍去调用了glibc的底层接口导致的。</p> 
<p>如下是亚马逊工程师对此仓库中底层OpenJDK8源码做的patch修复。</p> 
<p>https://git.alpinelinux.org/aports/tree/community/openjdk8/icedtea-issue13032.patch</p> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/24556836ae1de9c7abef9fe49dfd6afc.png" alt="img"></p> 
<h3><a id="3__23"></a>3. 解决方法</h3> 
<p>解决方法有以下几种：</p> 
<h4><a id="1_docker__27"></a>方案1、添加 docker 启动参数</h4> 
<p>启动容器命令参考如下：</p> 
<pre><code class="prism language-bash"><span class="token function">docker</span> run -d --init 省略其他参数镜像名等
</code></pre> 
<h4><a id="2tini__35"></a>方案2、镜像安装tini，由它管理进程 （推荐）</h4> 
<p>Dockerfile中使用如下方式</p> 
<pre><code class="prism language-bash">RUN apk --update --no-cache <span class="token function">add</span> tini 
<span class="token comment">#利用ENTRYPOINT一定会执行的特点，将它作为PID=1托管进程</span>
ENTRYPOINT <span class="token punctuation">[</span><span class="token string">"tini"</span><span class="token punctuation">]</span>
CMD java <span class="token variable">$JAVA_OPTS</span> -jar app.jar
</code></pre> 
<h4><a id="3ShellJava_46"></a>方案3、用Shell脚本启动Java进程</h4> 
<p>编写脚本 <code>docker-entrypoint.sh</code></p> 
<pre><code class="prism language-bash"><span class="token comment"># !/bin/bash</span>
java <span class="token variable">$JAVA_OPTS</span> -jar app.jar
</code></pre> 
<p>Dockerfile中使用如下方式</p> 
<pre><code class="prism language-bash">CMD /docker-entrypoint.sh
</code></pre> 
<p>不能写为下面方式，否则java进程的pid是1：</p> 
<pre><code>ENTRYPOINT exec java $JAVA_OPTS -jar app.jar
</code></pre> 
<h4><a id="4glibc_67"></a>方案4、安装glibc</h4> 
<p>https://github.com/sgerrand/alpine-pkg-glibc</p> 
<p>此方案仅适用于X86_64 CPU架构，分在线与离线安装两种方法，以下举例说明</p> 
<p>Dockerfile中在线安装：</p> 
<pre><code class="prism language-bash">RUN <span class="token function">curl</span> -kLo /etc/apk/keys/sgerrand.rsa.pub  https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub <span class="token operator">&amp;&amp;</span> <span class="token punctuation">\</span>
    <span class="token function">curl</span> -kLo glibc-2.35-r0.apk https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.35-r0/glibc-2.35-r0.apk <span class="token operator">&amp;&amp;</span> <span class="token punctuation">\</span>
    apk <span class="token function">add</span> glibc-2.35-r0.apk <span class="token operator">&amp;&amp;</span> <span class="token punctuation">\</span>
    <span class="token function">rm</span> -f glibc-2.35-r0.apk
</code></pre> 
<h4><a id="5glibc_82"></a>方案5、换一种基于glibc的镜像</h4> 
<p>如 debian、ubuntu、centos等基础镜像封装</p> 
<h4><a id="_86"></a>参考</h4> 
<p>https://blog.csdn.net/agonie201218/article/details/127119359</p>
                </div>
            </body>
            </html>
            